package com.niiwoo.civet.user.service.local.sms;

import com.niiwoo.civet.system.service.SysParamService;
import com.niiwoo.civet.user.constants.LoginAccountErrorCode;
import com.niiwoo.civet.user.dao.entity.SMSRecord;
import com.niiwoo.civet.user.dto.request.RefreshSMSCodeRequestDTO;
import com.niiwoo.civet.user.enums.UserSMSTypeEnum;
import com.niiwoo.civet.user.service.duboo.UserSystemConfigurable;
import com.niiwoo.civet.user.service.local.UserSMSService;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import com.niiwoo.tripod.sms.ISmsSendService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.concurrent.FutureCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.Date;
import java.util.Optional;
import java.util.Random;

@Slf4j
public abstract class AbstractSMSSender implements SMSContentTemplate, UserSystemConfigurable {

    private SysParamService sysParamService;

    @Autowired
    protected UserSMSService userSMSLocalService;

    @Autowired
    protected SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    protected PrivacyMasks privacyMasks;

    @Autowired
    protected ISmsSendService smsSendService;

    @Value(value = "${smsService.enable:false}")
    private Boolean enable;

    public static final String DEFAULT_AUTH_CODE = "888888";

    protected SMSResult sendSMS(RefreshSMSCodeRequestDTO requestDTO) {
        SMSConfigItem smsConfigItem = getSMSConfigItem(requestDTO.getSmsType()).orElse(null);
        beforeSend(requestDTO, smsConfigItem);
        if(enable) {
            SMSRecord record = generateSMSRecord(requestDTO.getLoginMobileNo(), requestDTO.getSmsType());
            smsSendService.doSend(requestDTO.getLoginMobileNo(), getContent(requestDTO, record), 0, new FutureCallback<Boolean>() {
                @Override
                public void completed(Boolean success) {
                    if (success) {
                        log.info("短信###发送成功, mobileNo={}, type={}", requestDTO.getLoginMobileNo(), requestDTO.getSmsType());
                        afterSendSuccess(requestDTO, record, smsConfigItem);
                    } else {
                        log.error("短信###发送失败, mobileNo={}, type={}", requestDTO.getLoginMobileNo(), requestDTO.getSmsType());
                    }
                }

                @Override
                public void failed(Exception e) {
                    log.error(String.format("短信###发送异常, mobileNo=%s, type=%s, exceptionMessage=%s", requestDTO.getLoginMobileNo(), requestDTO.getSmsType(), e.getMessage()), e);
                }

                @Override
                public void cancelled() {

                }
            });
            return new SMSResult(true, record.getAuthCode());
        } else {
            SMSRecord record = new SMSRecord();
            record.setAuthCode(DEFAULT_AUTH_CODE);
            afterSendSuccess(requestDTO, record, smsConfigItem);
            return new SMSResult(true, record.getAuthCode());
        }
    }

    abstract protected void beforeSend(RefreshSMSCodeRequestDTO requestDTO, SMSConfigItem smsConfigItem);

    abstract protected String getContent(RefreshSMSCodeRequestDTO requestDTO, SMSRecord record);

    abstract protected void afterSendSuccess(RefreshSMSCodeRequestDTO requestDTO, SMSRecord record, SMSConfigItem configItem);

    abstract protected UserSMSTypeEnum getType();

    abstract public void removeAuthCodeCache(String mobileNo);

    abstract public boolean isAuthCodeCacheRight(String mobileNo, String exceptCode);

    abstract public void removeDayTimesCache(String mobileNo);

    abstract public void removeMonthTimesCache(String mobileNo);

    /**
     * 创建短信记录
     *
     * @param loginMobile 手机号
     * @param type 业务类型
     */
    private SMSRecord generateSMSRecord(String loginMobile, UserSMSTypeEnum type) {
        SMSRecord smsRecord = new SMSRecord();
        smsRecord.setId(snowflakeIdWorker.nextId());
        smsRecord.setMobileNo(privacyMasks.encryptPrivacy(loginMobile));
        smsRecord.setAuthCode(genRandomNumber());
        smsRecord.setBusinessType(type.getValue());
        smsRecord.setCreateTime(new Date());
        if (!userSMSLocalService.save(smsRecord)) {
            throw new BizException(LoginAccountErrorCode.SMS_RECORD_CREATE_FAIL);
        }
        return smsRecord;
    }

    /**
     * 随机生成数字验证码
     */
    private String genRandomNumber() {
        char[] charPool = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
        int count = charPool.length;
        Random random = new Random();
        StringBuilder builder = new StringBuilder();

        for (int i = 0; i < 6; ++i) {
            int index = random.nextInt(count);
            builder.append(charPool[index]);
        }

        return builder.toString();
    }

    /**
     * 获取短信配置项
     *
     * @param type 短信类型
     */
    private Optional<SMSConfigItem> getSMSConfigItem(UserSMSTypeEnum type) {
        return getSysConfList(SMS_CONFIGURATION, SMSConfigItem.class).flatMap(smsConfigItems -> smsConfigItems.stream().filter(item -> item.getType() == type).findFirst());
    }

    public void setSysParamService(SysParamService sysParamService) {
        this.sysParamService = sysParamService;
    }

    @Override
    public SysParamService getSysParamService() {
        return sysParamService;
    }

}
